跳到主要内容

白屏、首屏慢如何排查与优化?

考察点​

  • 桌面端特有的白屏成因(与 Web 不同)
  • 系统化的首屏优化手段

参考答案​

1. 先分层定位:白屏发生在哪一环​

主进程 ready → 创建窗口 → 加载页面 → preload 执行 → 页面 JS 执行 → 首屏渲染
① ② ③ ④ ⑤ ⑥

逐环排查:

  • ①② 主进程慢:ready 前做了重活(同步 IO、模块 require 过多)
  • ③ 加载慢:远程 URL 网络慢 / 本地文件被 asar 读取阻塞 / 协议 handler 慢
  • ④ preload 慢或报错:同步重逻辑、报错导致桥缺失(页面依赖 api 而卡死)
  • ⑤ JS 执行慢:bundle 太大、首屏依赖链太长
  • ⑥ 渲染慢:首屏请求数据串行、字体/图片阻塞

2. 立即见效的手段​

(1)show: false + ready-to-show(消灭"白屏观感")

const win = new BrowserWindow({
show: false, // 先不显示,避免用户看到加载过程的白屏
backgroundColor: '#1e1e1e', // 与页面底色一致,加载底色不突兀
});

win.once('ready-to-show', () => {
win.show(); // 首帧渲染完成再显示
});

(2)骨架屏/启动画面内联 窗口创建立刻加载一个极简 loading 页(内联 data URI 或独立轻量 html),主 bundle ready 后切换,用户感知从"白屏"变"启动动画"。

(3)主进程建窗时机优化

// ❌ ready 里做一堆事再建窗
app.whenReady().then(async () => {
await initDatabase(); // 耗时
await loadConfig(); // 耗时
createWindow(); // 窗口迟迟不建
});

// ✅ 先建窗(loading 页),初始化并行,完成后再通知页面
app.whenReady().then(() => {
createWindow(); // 立即显示骨架
Promise.all([initDatabase(), loadConfig()]).then(() => {
win.webContents.send('app:ready');
});
});

3. 加载链路优化​

(1)资源本地化:生产环境页面、图片、字体全部本地加载(自定义协议),零网络依赖——这是桌面端相对 Web 的天然优势

(2)bundle 优化(与 Web 同理):

  • 路由级代码分割,首屏只加载必要 chunk
  • 依赖分析(rollup-plugin-visualizer),砍掉误入首屏的大依赖
  • 首屏关键 CSS 内联

(3)preload 瘦身:preload 顶层同步代码阻塞页面加载,重活全部异步化

(4)数据加载并行化:首屏数据从"页面 mount 后串行请求"改为"主进程预取 + 页面 invoke 拿缓存"

4. 量化与监控​

// 主进程记录建窗耗时
const t0 = Date.now();
win.once('ready-to-show', () => {
logger.info(`首窗耗时: ${Date.now() - t0}ms`);
});

// 渲染进程记录 Web 指标
new PerformanceObserver((list) => {
for (const entry of list.getEntries()) {
// FCP / LCP 上报
report({ name: entry.name, value: entry.startTime });
}
}).observe({ type: 'paint', buffered: true });

建立"启动耗时"基线指标,每次发版对比,防劣化。

5. 特殊场景的白屏​

场景原因对策
打包后白屏(dev 正常)路径错误/preload 未打包/协议未注册解 asar 检查、看主进程日志
偶发白屏渲染进程 OOM 崩溃render-process-gone 监听 + 重载
唤醒后白屏GPU 进程异常disable-gpu 排查、Chromium 版本问题
高分屏白屏闪烁GPU 光栅化问题特定硬件 --disable-gpu-rasterization 类开关兜底

6. 面试话术​

排查先按"建窗→加载→preload→JS→渲染"五环定位。优化上,观感层用 show:false + ready-to-show + 背景色 + 骨架屏;链路层用资源本地化、preload 瘦身、主进程初始化与建窗并行、bundle 分割;最后用启动耗时埋点建基线防劣化。打包后白屏第一嫌疑人永远是路径和协议注册。

常见追问​

  • 骨架屏怎么和主页面切换不闪? 同窗口内 loading 页作为主页面的一部分(一个 html 里的 loading 态),而不是两个页面跳转。
  • 远程 URL 场景白屏还有什么手段? 预连接(webContents 预热)、离线缓存(service worker / session 缓存)、加载超时降级页。